home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / pp.rb < prev    next >
Text File  |  2007-06-07  |  16KB  |  655 lines

  1. # == Pretty-printer for Ruby objects.
  2. # = Which seems better?
  3. # non-pretty-printed output by #p is:
  4. #   #<PP:0x81fedf0 @genspace=#<Proc:0x81feda0>, @group_queue=#<PrettyPrint::GroupQueue:0x81fed3c @queue=[[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], []]>, @buffer=[], @newline="\n", @group_stack=[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], @buffer_width=0, @indent=0, @maxwidth=79, @output_width=2, @output=#<IO:0x8114ee4>>
  5. # pretty-printed output by #pp is:
  6. #   #<PP:0x81fedf0
  7. #    @buffer=[],
  8. #    @buffer_width=0,
  9. #    @genspace=#<Proc:0x81feda0>,
  10. #    @group_queue=
  11. #     #<PrettyPrint::GroupQueue:0x81fed3c
  12. #      @queue=
  13. #       [[#<PrettyPrint::Group:0x81fed78 @break=false, @breakables=[], @depth=0>],
  14. #        []]>,
  15. #    @group_stack=
  16. #     [#<PrettyPrint::Group:0x81fed78 @break=false, @breakables=[], @depth=0>],
  17. #    @indent=0,
  18. #    @maxwidth=79,
  19. #    @newline="\n",
  20. #    @output=#<IO:0x8114ee4>,
  21. #    @output_width=2>
  22. # I like the latter.  If you do too, this library is for you.
  23. # = Usage
  24. #   pp(obj)
  25. #
  26. # output +obj+ to +$>+ in pretty printed format.
  27. # It returns +nil+.
  28. # = Output Customization
  29. # To define your customized pretty printing function for your classes,
  30. # redefine a method #pretty_print(+pp+) in the class.
  31. # It takes an argument +pp+ which is an instance of the class PP.
  32. # The method should use PP#text, PP#breakable, PP#nest, PP#group and
  33. # PP#pp to print the object.
  34. #
  35. # = Author
  36. # Tanaka Akira <akr@m17n.org>
  37.  
  38. require 'prettyprint'
  39.  
  40. module Kernel
  41.   # returns a pretty printed object as a string.
  42.   def pretty_inspect
  43.     PP.pp(self, '')
  44.   end
  45.  
  46.   private
  47.   # prints arguments in pretty form.
  48.   #
  49.   # pp returns nil.
  50.   def pp(*objs) # :doc:
  51.     objs.each {|obj|
  52.       PP.pp(obj)
  53.     }
  54.     nil
  55.   end
  56.   module_function :pp
  57. end
  58.  
  59. class PP < PrettyPrint
  60.   # Outputs +obj+ to +out+ in pretty printed format of
  61.   # +width+ columns in width.
  62.   # 
  63.   # If +out+ is omitted, +$>+ is assumed.
  64.   # If +width+ is omitted, 79 is assumed.
  65.   # 
  66.   # PP.pp returns +out+.
  67.   def PP.pp(obj, out=$>, width=79)
  68.     q = PP.new(out, width)
  69.     q.guard_inspect_key {q.pp obj}
  70.     q.flush
  71.     #$pp = q
  72.     out << "\n"
  73.   end
  74.  
  75.   # Outputs +obj+ to +out+ like PP.pp but with no indent and
  76.   # newline.
  77.   # 
  78.   # PP.singleline_pp returns +out+.
  79.   def PP.singleline_pp(obj, out=$>)
  80.     q = SingleLine.new(out)
  81.     q.guard_inspect_key {q.pp obj}
  82.     q.flush
  83.     out
  84.   end
  85.  
  86.   # :stopdoc:
  87.   def PP.mcall(obj, mod, meth, *args, &block)
  88.     mod.instance_method(meth).bind(obj).call(*args, &block)
  89.   end
  90.   # :startdoc:
  91.  
  92.   @sharing_detection = false
  93.   class << self
  94.     # Returns the sharing detection flag as a boolean value.
  95.     # It is false by default.
  96.     attr_accessor :sharing_detection
  97.   end
  98.  
  99.   module PPMethods
  100.     InspectKey = :__inspect_key__
  101.  
  102.     def guard_inspect_key
  103.       if Thread.current[InspectKey] == nil
  104.         Thread.current[InspectKey] = []
  105.       end
  106.  
  107.       save = Thread.current[InspectKey]
  108.  
  109.       begin
  110.         Thread.current[InspectKey] = []
  111.         yield
  112.       ensure
  113.         Thread.current[InspectKey] = save
  114.       end
  115.     end
  116.  
  117.     # Adds +obj+ to the pretty printing buffer
  118.     # using Object#pretty_print or Object#pretty_print_cycle.
  119.     # 
  120.     # Object#pretty_print_cycle is used when +obj+ is already
  121.     # printed, a.k.a the object reference chain has a cycle.
  122.     def pp(obj)
  123.       id = obj.__id__
  124.  
  125.       if Thread.current[InspectKey].include? id
  126.         group {obj.pretty_print_cycle self}
  127.         return
  128.       end
  129.  
  130.       begin
  131.         Thread.current[InspectKey] << id
  132.         group {obj.pretty_print self}
  133.       ensure
  134.         Thread.current[InspectKey].pop unless PP.sharing_detection
  135.       end
  136.     end
  137.  
  138.     # A convenience method which is same as follows:
  139.     # 
  140.     #   group(1, '#<' + obj.class.name, '>') { ... }
  141.     def object_group(obj, &block) # :yield:
  142.       group(1, '#<' + obj.class.name, '>', &block)
  143.     end
  144.  
  145.     def object_address_group(obj, &block)
  146.       id = "%x" % (obj.__id__ * 2)
  147.       id.sub!(/\Af(?=[[:xdigit:]]{2}+\z)/, '') if id.sub!(/\A\.\./, '')
  148.       group(1, "\#<#{obj.class}:0x#{id}", '>', &block)
  149.     end
  150.  
  151.     # A convenience method which is same as follows:
  152.     # 
  153.     #   text ','
  154.     #   breakable
  155.     def comma_breakable
  156.       text ','
  157.       breakable
  158.     end
  159.  
  160.     # Adds a separated list.
  161.     # The list is separated by comma with breakable space, by default.
  162.     # 
  163.     # #seplist iterates the +list+ using +iter_method+.
  164.     # It yields each object to the block given for #seplist.
  165.     # The procedure +separator_proc+ is called between each yields.
  166.     # 
  167.     # If the iteration is zero times, +separator_proc+ is not called at all.
  168.     # 
  169.     # If +separator_proc+ is nil or not given,
  170.     # +lambda { comma_breakable }+ is used.
  171.     # If +iter_method+ is not given, :each is used.
  172.     # 
  173.     # For example, following 3 code fragments has similar effect.
  174.     # 
  175.     #   q.seplist([1,2,3]) {|v| xxx v }
  176.     # 
  177.     #   q.seplist([1,2,3], lambda { comma_breakable }, :each) {|v| xxx v }
  178.     # 
  179.     #   xxx 1
  180.     #   q.comma_breakable
  181.     #   xxx 2
  182.     #   q.comma_breakable
  183.     #   xxx 3
  184.     def seplist(list, sep=nil, iter_method=:each) # :yield: element
  185.       sep ||= lambda { comma_breakable }
  186.       first = true
  187.       list.__send__(iter_method) {|*v|
  188.         if first
  189.           first = false
  190.         else
  191.           sep.call
  192.         end
  193.         yield(*v)
  194.       }
  195.     end
  196.  
  197.     def pp_object(obj)
  198.       object_address_group(obj) {
  199.         seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v|
  200.           breakable
  201.           v = v.to_s if Symbol === v
  202.           text v
  203.           text '='
  204.           group(1) {
  205.             breakable ''
  206.             pp(obj.instance_eval(v))
  207.           }
  208.         }
  209.       }
  210.     end
  211.  
  212.     def pp_hash(obj)
  213.       group(1, '{', '}') {
  214.         seplist(obj, nil, :each_pair) {|k, v|
  215.           group {
  216.             pp k
  217.             text '=>'
  218.             group(1) {
  219.               breakable ''
  220.               pp v
  221.             }
  222.           }
  223.         }
  224.       }
  225.     end
  226.   end
  227.  
  228.   include PPMethods
  229.  
  230.   class SingleLine < PrettyPrint::SingleLine
  231.     include PPMethods
  232.   end
  233.  
  234.   module ObjectMixin
  235.     # 1. specific pretty_print
  236.     # 2. specific inspect
  237.     # 3. specific to_s if instance variable is empty
  238.     # 4. generic pretty_print
  239.  
  240.     # A default pretty printing method for general objects.
  241.     # It calls #pretty_print_instance_variables to list instance variables.
  242.     # 
  243.     # If +self+ has a customized (redefined) #inspect method,
  244.     # the result of self.inspect is used but it obviously has no
  245.     # line break hints.
  246.     # 
  247.     # This module provides predefined #pretty_print methods for some of
  248.     # the most commonly used built-in classes for convenience.
  249.     def pretty_print(q)
  250.       if /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:inspect).inspect
  251.         q.text self.inspect
  252.       elsif /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:to_s).inspect && instance_variables.empty?
  253.         q.text self.to_s
  254.       else
  255.         q.pp_object(self)
  256.       end
  257.     end
  258.  
  259.     # A default pretty printing method for general objects that are
  260.     # detected as part of a cycle.
  261.     def pretty_print_cycle(q)
  262.       q.object_address_group(self) {
  263.         q.breakable
  264.         q.text '...'
  265.       }
  266.     end
  267.  
  268.     # Returns a sorted array of instance variable names.
  269.     # 
  270.     # This method should return an array of names of instance variables as symbols or strings as:
  271.     # +[:@a, :@b]+.
  272.     def pretty_print_instance_variables
  273.       instance_variables.sort
  274.     end
  275.  
  276.     # Is #inspect implementation using #pretty_print.
  277.     # If you implement #pretty_print, it can be used as follows.
  278.     # 
  279.     #   alias inspect pretty_print_inspect
  280.     #
  281.     # However, doing this requires that every class that #inspect is called on
  282.     # implement #pretty_print, or a RuntimeError will be raised.
  283.     def pretty_print_inspect
  284.       if /\(PP::ObjectMixin\)#/ =~ Object.instance_method(:method).bind(self).call(:pretty_print).inspect
  285.         raise "pretty_print is not overridden for #{self.class}"
  286.       end
  287.       PP.singleline_pp(self, '')
  288.     end
  289.   end
  290. end
  291.  
  292. class Array
  293.   def pretty_print(q)
  294.     q.group(1, '[', ']') {
  295.       q.seplist(self) {|v|
  296.         q.pp v
  297.       }
  298.     }
  299.   end
  300.  
  301.   def pretty_print_cycle(q)
  302.     q.text(empty? ? '[]' : '[...]')
  303.   end
  304. end
  305.  
  306. class Hash
  307.   def pretty_print(q)
  308.     q.pp_hash self
  309.   end
  310.  
  311.   def pretty_print_cycle(q)
  312.     q.text(empty? ? '{}' : '{...}')
  313.   end
  314. end
  315.  
  316. class << ENV
  317.   def pretty_print(q)
  318.     q.pp_hash self
  319.   end
  320. end
  321.  
  322. class Struct
  323.   def pretty_print(q)
  324.     q.group(1, '#<struct ' + PP.mcall(self, Kernel, :class).name, '>') {
  325.       q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
  326.         q.breakable
  327.         q.text member.to_s
  328.         q.text '='
  329.         q.group(1) {
  330.           q.breakable ''
  331.           q.pp self[member]
  332.         }
  333.       }
  334.     }
  335.   end
  336.  
  337.   def pretty_print_cycle(q)
  338.     q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
  339.   end
  340. end
  341.  
  342. class Range
  343.   def pretty_print(q)
  344.     q.pp self.begin
  345.     q.breakable ''
  346.     q.text(self.exclude_end? ? '...' : '..')
  347.     q.breakable ''
  348.     q.pp self.end
  349.   end
  350. end
  351.  
  352. class File
  353.   class Stat
  354.     def pretty_print(q)
  355.       require 'etc.so'
  356.       q.object_group(self) {
  357.         q.breakable
  358.         q.text sprintf("dev=0x%x", self.dev); q.comma_breakable
  359.         q.text "ino="; q.pp self.ino; q.comma_breakable
  360.         q.group {
  361.           m = self.mode
  362.           q.text sprintf("mode=0%o", m)
  363.           q.breakable
  364.           q.text sprintf("(%s %c%c%c%c%c%c%c%c%c)",
  365.             self.ftype,
  366.             (m & 0400 == 0 ? ?- : ?r),
  367.             (m & 0200 == 0 ? ?- : ?w),
  368.             (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
  369.                              (m & 04000 == 0 ? ?x : ?s)),
  370.             (m & 0040 == 0 ? ?- : ?r),
  371.             (m & 0020 == 0 ? ?- : ?w),
  372.             (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
  373.                              (m & 02000 == 0 ? ?x : ?s)),
  374.             (m & 0004 == 0 ? ?- : ?r),
  375.             (m & 0002 == 0 ? ?- : ?w),
  376.             (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
  377.                              (m & 01000 == 0 ? ?x : ?t)))
  378.         }
  379.         q.comma_breakable
  380.         q.text "nlink="; q.pp self.nlink; q.comma_breakable
  381.         q.group {
  382.           q.text "uid="; q.pp self.uid
  383.           begin
  384.             pw = Etc.getpwuid(self.uid)
  385.           rescue ArgumentError
  386.           end
  387.           if pw
  388.             q.breakable; q.text "(#{pw.name})"
  389.           end
  390.         }
  391.         q.comma_breakable
  392.         q.group {
  393.           q.text "gid="; q.pp self.gid
  394.           begin
  395.             gr = Etc.getgrgid(self.gid)
  396.           rescue ArgumentError
  397.           end
  398.           if gr
  399.             q.breakable; q.text "(#{gr.name})"
  400.           end
  401.         }
  402.         q.comma_breakable
  403.         q.group {
  404.           q.text sprintf("rdev=0x%x", self.rdev)
  405.           q.breakable
  406.           q.text sprintf('(%d, %d)', self.rdev_major, self.rdev_minor)
  407.         }
  408.         q.comma_breakable
  409.         q.text "size="; q.pp self.size; q.comma_breakable
  410.         q.text "blksize="; q.pp self.blksize; q.comma_breakable
  411.         q.text "blocks="; q.pp self.blocks; q.comma_breakable
  412.         q.group {
  413.           t = self.atime
  414.           q.text "atime="; q.pp t
  415.           q.breakable; q.text "(#{t.tv_sec})"
  416.         }
  417.         q.comma_breakable
  418.         q.group {
  419.           t = self.mtime
  420.           q.text "mtime="; q.pp t
  421.           q.breakable; q.text "(#{t.tv_sec})"
  422.         }
  423.         q.comma_breakable
  424.         q.group {
  425.           t = self.ctime
  426.           q.text "ctime="; q.pp t
  427.           q.breakable; q.text "(#{t.tv_sec})"
  428.         }
  429.       }
  430.     end
  431.   end
  432. end
  433.  
  434. class MatchData
  435.   def pretty_print(q)
  436.     q.object_group(self) {
  437.       q.breakable
  438.       q.seplist(1..self.size, lambda { q.breakable }) {|i|
  439.         q.pp self[i-1]
  440.       }
  441.     }
  442.   end
  443. end
  444.  
  445. class Object
  446.   include PP::ObjectMixin
  447. end
  448.  
  449. [Numeric, Symbol, FalseClass, TrueClass, NilClass, Module].each {|c|
  450.   c.class_eval {
  451.     def pretty_print_cycle(q)
  452.       q.text inspect
  453.     end
  454.   }
  455. }
  456.  
  457. [Numeric, FalseClass, TrueClass, Module].each {|c|
  458.   c.class_eval {
  459.     def pretty_print(q)
  460.       q.text inspect
  461.     end
  462.   }
  463. }
  464.  
  465. # :enddoc:
  466. if __FILE__ == $0
  467.   require 'test/unit'
  468.  
  469.   class PPTest < Test::Unit::TestCase
  470.     def test_list0123_12
  471.       assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], '', 12))
  472.     end
  473.  
  474.     def test_list0123_11
  475.       assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], '', 11))
  476.     end
  477.  
  478.     OverriddenStruct = Struct.new("OverriddenStruct", :members, :class)
  479.     def test_struct_override_members # [ruby-core:7865]
  480.       a = OverriddenStruct.new(1,2)
  481.       assert_equal("#<struct Struct::OverriddenStruct members=1, class=2>\n", PP.pp(a, ''))
  482.     end
  483.  
  484.     def test_redefined_method
  485.       o = ""
  486.       def o.method
  487.       end
  488.       assert_equal(%(""\n), PP.pp(o, ""))
  489.     end
  490.   end
  491.  
  492.   class HasInspect
  493.     def initialize(a)
  494.       @a = a
  495.     end
  496.  
  497.     def inspect
  498.       return "<inspect:#{@a.inspect}>"
  499.     end
  500.   end
  501.  
  502.   class HasPrettyPrint
  503.     def initialize(a)
  504.       @a = a
  505.     end
  506.  
  507.     def pretty_print(q)
  508.       q.text "<pretty_print:"
  509.       q.pp @a
  510.       q.text ">"
  511.     end
  512.   end
  513.  
  514.   class HasBoth
  515.     def initialize(a)
  516.       @a = a
  517.     end
  518.  
  519.     def inspect
  520.       return "<inspect:#{@a.inspect}>"
  521.     end
  522.  
  523.     def pretty_print(q)
  524.       q.text "<pretty_print:"
  525.       q.pp @a
  526.       q.text ">"
  527.     end
  528.   end
  529.  
  530.   class PrettyPrintInspect < HasPrettyPrint
  531.     alias inspect pretty_print_inspect
  532.   end
  533.  
  534.   class PrettyPrintInspectWithoutPrettyPrint
  535.     alias inspect pretty_print_inspect
  536.   end
  537.  
  538.   class PPInspectTest < Test::Unit::TestCase
  539.     def test_hasinspect
  540.       a = HasInspect.new(1)
  541.       assert_equal("<inspect:1>\n", PP.pp(a, ''))
  542.     end
  543.  
  544.     def test_hasprettyprint
  545.       a = HasPrettyPrint.new(1)
  546.       assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
  547.     end
  548.  
  549.     def test_hasboth
  550.       a = HasBoth.new(1)
  551.       assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
  552.     end
  553.  
  554.     def test_pretty_print_inspect
  555.       a = PrettyPrintInspect.new(1)
  556.       assert_equal("<pretty_print:1>", a.inspect)
  557.       a = PrettyPrintInspectWithoutPrettyPrint.new
  558.       assert_raise(RuntimeError) { a.inspect }
  559.     end
  560.  
  561.     def test_proc
  562.       a = proc {1}
  563.       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
  564.     end
  565.  
  566.     def test_to_s_with_iv
  567.       a = Object.new
  568.       def a.to_s() "aaa" end
  569.       a.instance_eval { @a = nil }
  570.       result = PP.pp(a, '')
  571.       assert_equal("#{a.inspect}\n", result)
  572.       assert_match(/\A#<Object.*>\n\z/m, result)
  573.       a = 1.0
  574.       a.instance_eval { @a = nil }
  575.       result = PP.pp(a, '')
  576.       assert_equal("#{a.inspect}\n", result)
  577.     end
  578.     
  579.     def test_to_s_without_iv
  580.       a = Object.new
  581.       def a.to_s() "aaa" end
  582.       result = PP.pp(a, '')
  583.       assert_equal("#{a.inspect}\n", result)
  584.       assert_equal("aaa\n", result)
  585.     end
  586.   end
  587.  
  588.   class PPCycleTest < Test::Unit::TestCase
  589.     def test_array
  590.       a = []
  591.       a << a
  592.       assert_equal("[[...]]\n", PP.pp(a, ''))
  593.       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
  594.     end
  595.  
  596.     def test_hash
  597.       a = {}
  598.       a[0] = a
  599.       assert_equal("{0=>{...}}\n", PP.pp(a, ''))
  600.       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
  601.     end
  602.  
  603.     S = Struct.new("S", :a, :b)
  604.     def test_struct
  605.       a = S.new(1,2)
  606.       a.b = a
  607.       assert_equal("#<struct Struct::S a=1, b=#<struct Struct::S:...>>\n", PP.pp(a, ''))
  608.       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
  609.     end
  610.  
  611.     def test_object
  612.       a = Object.new
  613.       a.instance_eval {@a = a}
  614.       assert_equal(a.inspect + "\n", PP.pp(a, ''))
  615.     end
  616.  
  617.     def test_anonymous
  618.       a = Class.new.new
  619.       assert_equal(a.inspect + "\n", PP.pp(a, ''))
  620.     end
  621.  
  622.     def test_withinspect
  623.       a = []
  624.       a << HasInspect.new(a)
  625.       assert_equal("[<inspect:[...]>]\n", PP.pp(a, ''))
  626.       assert_equal("#{a.inspect}\n", PP.pp(a, ''))
  627.     end
  628.  
  629.     def test_share_nil
  630.       begin
  631.         PP.sharing_detection = true
  632.         a = [nil, nil]
  633.         assert_equal("[nil, nil]\n", PP.pp(a, ''))
  634.       ensure
  635.         PP.sharing_detection = false
  636.       end
  637.     end
  638.   end
  639.  
  640.   class PPSingleLineTest < Test::Unit::TestCase
  641.     def test_hash
  642.       assert_equal("{1=>1}", PP.singleline_pp({ 1 => 1}, '')) # [ruby-core:02699]
  643.       assert_equal("[1#{', 1'*99}]", PP.singleline_pp([1]*100, ''))
  644.     end
  645.   end
  646. end
  647.